package org.redmagic.service.utils;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Collections;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.servlet.http.HttpServletRequest;

import org.redmagic.service.domain.Property;

import com.google.common.base.Joiner;
import com.google.common.base.Splitter;

public final class PropertyUtils {

    private static final String SINGLE_TAG = "tags";
    private static final String BLUEMAGIC_GROUP = "bluemagic:group";
    
    private static final Splitter TAGS_SPLITTER = Splitter.on("&").trimResults().omitEmptyStrings();
    private static final Splitter SINGLE_TAG_SPLITTER = Splitter.on(",").trimResults().omitEmptyStrings();
    
    private static final Joiner TAGS_JOINER = Joiner.on("&");
    private static final Joiner SINGLE_TAG_JOINER = Joiner.on(",");
    
    public static Property create(HttpServletRequest request, String context) {
        String placeholder = getProperty(request, context);
        Set<String> tags = getTags(request);
        String group = getGroup(tags);
        Property property = new Property(placeholder, tags, group);
        return property;
    }
    
    private static String getProperty(HttpServletRequest request, String context) {
        String contextPath = request.getContextPath();
        int length = (contextPath + context).length();
        String decoded = decode(request.getRequestURI());
        int queryIndex = decoded.indexOf("?");
        if (queryIndex > -1) {
            return decoded.substring(length, queryIndex);
        } else {
            return decoded.substring(length);
        }
    }

    private static Set<String> getTags(HttpServletRequest request) {
        String tagString = findTagString(request);

        Set<String> tags = Collections.emptySet();
        if (tagString != null && !tagString.trim().isEmpty()) {
            tagString = decode(tagString);
            tags = parseTags(tagString);
        }

        return tags;
    }
    
    private static String findTagString(HttpServletRequest request) {
        String queryString = request.getQueryString();
        if (queryString == null) {
            // it might be encoded
            String requestUri = decode(request.getRequestURI());
            return getTagsFromDecodedUri(requestUri);
        } else {
            return queryString;
        }
    }

    private static String getTagsFromDecodedUri(String requestUri) {
        if (requestUri.contains("?")) {
            int index = requestUri.indexOf("?");
            return requestUri.substring(index + 1);
        } else {
            return null;
        }
    }

    private static String decode(String string) {
        try {
            return URLDecoder.decode(string, "UTF-8");
        } catch (UnsupportedEncodingException uee) {
            throw new RuntimeException(uee.getMessage(), uee);
        }
    }

    private static Set<String> parseTags(String tagString) {

        Iterable<String> allTags = TAGS_SPLITTER.split(tagString);

        SortedSet<String> results = new TreeSet<String>();
        for (String tags : allTags) {

            if (tags.startsWith(SINGLE_TAG + "=")) {
                tags = tags.replace(SINGLE_TAG + "=", "");
                Iterable<String> singleTags = SINGLE_TAG_SPLITTER.split(tags);
                for (String singleTag : singleTags) {
                    results.add(singleTag);
                }
            } else {
                results.add(tags);
            }
        }
        
        return results;
    }
    
    private static String getGroup(Set<String> tags) {
        String group = null;
        String groupTag = null;
        for (String tag : tags) {
            if (tag.startsWith(BLUEMAGIC_GROUP + "=")) {
                int index = tag.indexOf("=");
                group = tag.substring(index + 1);
                groupTag = tag;
            }
        }
        
        if (groupTag != null) {
            tags.remove(groupTag);
        }
        
        if (group == null) {
            group = "public";
        }
        return group;
    }

    public static String toUrlForm(Property property) {
        StringBuilder propertyUrl = new StringBuilder();
        propertyUrl.append(property.getPlaceholder());
        Set<String> tags = sortAndAddGroupToTags(property);
        propertyUrl.append("?");
        propertyUrl.append(TAGS_JOINER.join(tags));
        return propertyUrl.toString();
    }

    private static Set<String> sortAndAddGroupToTags(Property property) {
        SortedSet<String> tags = sortTags(property.getTags());
        tags.add(BLUEMAGIC_GROUP + "=" + property.getGroup());
        return tags;
    }

    private static SortedSet<String> sortTags(Set<String> tags) {
        SortedSet<String> sortedTags = new TreeSet<String>();
        SortedSet<String> sortedSingleTags = new TreeSet<String>();
        
        for (String tag : tags) {
            if (tag.contains("=")) {
                sortedTags.add(tag);
            } else {
                sortedSingleTags.add(tag);
            }
        }
        
        if (!sortedSingleTags.isEmpty()) {
            String singleTags = SINGLE_TAG_JOINER.join(sortedSingleTags);
            sortedTags.add(SINGLE_TAG + "=" + singleTags);            
        }
        return sortedTags;
    }
}